﻿using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Threading.Tasks;
using TranslatorService;

namespace YandexTranslator
{
	// Get API key from http://api.yandex.com/translate/
#pragma warning disable 1998
	public class YandexTranslator : ITranslatorService
	{
		private const string baseUrl = "https://translate.yandex.net/api/v1.5/tr.json";
		private string apiKey;

		public TranslatorServiceCapabilities ServiceCapabilities
		{
			get
			{
				return TranslatorServiceCapabilities.DefinesWords |
					TranslatorServiceCapabilities.DetectsLanguage |
					TranslatorServiceCapabilities.HtmlText |
					TranslatorServiceCapabilities.TranslatesPhrases |
					TranslatorServiceCapabilities.PlainText |
					TranslatorServiceCapabilities.TranslatesWords |
					TranslatorServiceCapabilities.RequiresAuthentication;
			}
		}

		public string ServiceName
		{
			get { return "Yandex Translator"; }
		}

		public Uri ServiceURI
		{
			get { return new Uri("http://api.yandex.com/translate/"); }
		}

		public string[] AuthenticationParameterDetail
		{
			get { return new string[] { "APIKey" }; }
		}

		public async Task<bool> AuthenticateAsync(params string[] options)
		{
			if (options.Length != 1)
				throw new ArgumentException();
			apiKey = options[0];
			return true;
		}

		public async Task<Dictionary<string, string>> GetSupportedLanguagesAsync(string locale = "en")
		{
			var d = new Dictionary<string, string>(100);
			var codes = await this.CallMethodAsync<string>("getLangs", "ui", locale);
			if (codes != null)
			{
				var json = (IDictionary<string, object>)SimpleJson.DeserializeObject(codes);
				foreach (var item in (JsonObject)json["langs"])
					d.Add(item.Key, item.Value.ToString());
			}
			return d;
		}

		public async Task<string> TranslateAsync(string sourceLang, string destLang, string value, InputFormat format = InputFormat.Text)
		{
			string lang = string.IsNullOrWhiteSpace(sourceLang) ? destLang : sourceLang + "-" + destLang;
			var resp = await CallMethodAsync<RootObject>("translate", "lang", lang, "format", format == InputFormat.Text ? "plain" : "html", "text", value);
			return resp.text[0];
		}

		public async Task<string> DetectLanguageAsync(string value)
		{
			var resp = await CallMethodAsync<DetectObject>("detect", "text", value);
			return resp.lang;
		}

		public async Task<T> CallMethodAsync<T>(string methodName, params string[] parameters) where T : class
		{
			if (string.IsNullOrWhiteSpace(apiKey))
				throw new UnauthorizedAccessException();

			string[] newParams = new string[parameters.Length + 2];
			parameters.CopyTo(newParams, 2);
			newParams[0] = "key";
			newParams[1] = apiKey;
			return await HttpUtility.CallJsonMethodAsync<T>(baseUrl, methodName, null, newParams);
		}

		[DataContract]
		internal class DetectObject
		{
			[DataMember]
			public int code { get; set; }
			[DataMember]
			public string lang { get; set; }
		}

		[DataContract]
		internal class RootObject
		{
			[DataMember]
			public int code { get; set; }
			[DataMember]
			public string lang { get; set; }
			[DataMember]
			public List<string> text { get; set; }
		}
	}
}
